package com.df.my_net_game.common.utils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class SnowflakeWorkIdAndDatacenterIdUtils {

    private static final long MAX_WORKER_ID = 31; // 5 bits
    private static final long MAX_DATACENTER_ID = 31; // 5 bits

    public static long getWorkerId() {
        try {
            InetAddress ip = getLocalHostLANAddress();
            byte[] ipAddressByteArray = ip.getAddress();
            long workerId = 0;
            for (byte b : ipAddressByteArray) {
                workerId += (b & 0xFF);
            }
            return workerId % (MAX_WORKER_ID + 1);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get worker ID", e);
        }
    }

    public static long getDatacenterId() {
        try {
            InetAddress ip = getLocalHostLANAddress();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            byte[] macAddressByteArray = network.getHardwareAddress();
            long datacenterId = 0;
            for (byte b : macAddressByteArray) {
                datacenterId += (b & 0xFF);
            }
            return datacenterId % (MAX_DATACENTER_ID + 1);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get datacenter ID", e);
        }
    }

    private static InetAddress getLocalHostLANAddress() throws Exception {
        try {
            InetAddress candidateAddress = null;
            // Iterate all NICs (network interface cards)...
            for (Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = ifaces.nextElement();
                // Iterate all IP addresses assigned to each card...
                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {
                        if (inetAddr.isSiteLocalAddress()) {
                            // Found non-loopback site-local address. Return it immediately...
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // Found non-loopback address, but not necessarily site-local.
                            // Store it as a candidate to be returned if site-local address is not subsequently found...
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // If no non-loopback address was found, fallback to localhost...
            return InetAddress.getLocalHost();
        } catch (Exception e) {
            throw new RuntimeException("Failed to determine LAN address", e);
        }
    }

    public static void main(String[] args) {
        long workerId = getWorkerId();
        long datacenterId = getDatacenterId();
        System.out.println("Worker ID: " + workerId);
        System.out.println("Datacenter ID: " + datacenterId);
    }
}